#ifndef __PRIMITIVERENDERERBASE__
#define __PRIMITIVERENDERERBASE__

#include "..\..\Math\Colorb.h"
#include "..\..\Math\Point3.h"
#include "..\..\Math\Matrix4.h"
#include "Face.h"
#include "Box.h"
#include "..\..\Math\MathHelper.h"
#include "RenderListBase.h"
#include "IProvideCaching.h"
#include "IProvideCulling.h"
#include "IProvidePosition.h"
#include "IProvideLighting.h"
#include "IReportProgress.h"

#include <cstdint>
#include <stack>
#include <vector>

class RendererBase;
class Schematic;
class Block;

class PrimitiveRendererBase
{
protected:
	RendererBase *_r;
	Matrix4f _m;
	std::vector<RenderListBase*> _renderLists;
	RenderListBase *_currentList;
	std::stack<Matrix4f> _states;

	virtual void SetupList(ITexture *texture);
	virtual RenderListBase *CreateRenderList();

public:
	IProvideCaching *CacheProvider;
	IProvideCulling *CullProvider;
	IProvidePosition *PositionProvider;
	IProvideLighting *LightProvider;
	IReportProgress *ProgressReporter;

	inline RendererBase *GetRenderer() { return _r; }

	PrimitiveRendererBase(RendererBase *r);
	virtual ~PrimitiveRendererBase() { };

	/// <summary>
	/// Translate the view matrix.
	/// </summary>
	/// <param name="x">X value.</param>
	/// <param name="y">Y value.</param>
	/// <param name="z">Z value.</param>
	virtual void Translate(const float &x, const float &y, const float &z);

	/// <summary>
	/// Rotate the view matrix.
	/// </summary>
	/// <param name="angle">Angle in degrees.</param>
	virtual void Rotate(const float &angle, const int &axisX, const int &axisY, const int &axisZ);

	/// <summary>
	/// Scale the view matrix.
	/// </summary>
	/// <param name="x">X scale.</param>
	/// <param name="y">Y scale.</param>
	/// <param name="z">Z scale.</param>
	virtual void Scale(const float &x, const float &y, const float &z);

	/// <summary>
	/// Save the current matrix state.
	/// </summary>
	virtual void PushState();

	/// <summary>
	/// Restore matching pushed matrix state.
	/// </summary>
	virtual void PopState();

	/// <summary>
	/// Draw this face to this primitive renderer.
	/// </summary>
	/// <param name="box">Face to draw.</param>
	/// <param name="reverse">True to draw both sides of this face.</param>
	virtual void Draw(const Face &face, const bool &reverse = false);

	/// <summary>
	/// Draw this box to this primitive renderer.
	/// </summary>
	/// <param name="box">Box to draw.</param>
	virtual void Draw(const Box &box);
	
	/// <summary>
	/// Called to compile the primitives.
	/// </summary>
	virtual void Compile(const bool &allowCacheLoading = false);

	/// <summary>
	/// Render this chunk render data.
	/// </summary>
	virtual void Render() = 0;

	void ExecuteRenderer(Schematic *schematic, const Block &block, const Point3i &position);
	bool IsFullBlockAt(const int &x, const int &y, const int &z);
	bool IsOpaqueBlockAt(const int &x, const int &y, const int &z);
};

#endif